#pragma once
//实现项目中的一些公共的工具类接口
//1.生成一个唯一的ID的接口
//2.文件的读写操作

#include <iostream>
#include <random>
#include <iomanip>
#include <atomic>
#include <fstream>
#include <sstream>
#include "logger.hpp"

namespace zrb
{
    std::string uuid()
    {
        //生成一个由16位随机字符组成的字符串作为唯一的ID
        //1.生成6个由0~255组成的随机数字（1字节转换为16进制字符） --- 生成12位16进制数字
        std::random_device rd; //实例化设备随机数对象 用于生成设备随机数
        std::mt19937 generator(rd()); //以设备随机数为种子，实例化伪随机数对象
        std::uniform_int_distribution<int> distributio(0,255); //限定随机数范围

        std::stringstream ss;
        for(int i = 0; i < 6; ++i)
        {
            if(i == 2) ss << '-';
            //转16进制 std::hex
            //不够两位就填充到两位 std::stew(2) << std::fill('0')
            ss << std::setw(2) << std::setfill('0') << std::hex << distributio(generator);
        }
        ss << '-';

        //2.通过一个原子变量生成一个2字节的编号数字 -- 生成4位16进制的数字字符
        static std::atomic<short> idx(0);
        short tmp = idx.fetch_add(1); //返回值 如何进行自增
        ss << std::setw(4) << std::setfill('0') << std::hex << tmp;

        return ss.str();
    }

    std::string vcode()
    {
        //1.生成6个由0~255组成的随机数字（1字节转换为16进制字符） --- 生成12位16进制数字
        std::random_device rd; //实例化设备随机数对象 用于生成设备随机数
        std::mt19937 generator(rd()); //以设备随机数为种子，实例化伪随机数对象
        std::uniform_int_distribution<int> distributio(0,9); //限定随机数范围

        std::stringstream ss;
        for(int i = 0; i < 4; ++i)
        {
            ss << distributio(generator);
        }

        return ss.str();
    }

    //读取文件
    bool readFile(const std::string& fileName,std::string& body)
    {
        std::ifstream ifs(fileName,std::ios::binary | std::ios::in);
        if(ifs.is_open() == false)
        {
            LOG_ERROR("打开{}文件失败",fileName); 
            return false;          
        }
        ifs.seekg(0,std::ios_base::end); //偏移到文件末尾
        size_t size = ifs.tellg();       //获取文件大小
        body.resize(size);
        ifs.seekg(0,std::ios_base::beg); //偏移到文件头部
        ifs.read(&body[0],size);         //读取文件
        if(ifs.good() == false)
        {
            LOG_ERROR("读取{}文件失败",fileName);
            ifs.close();
            return false;  
        }
        ifs.close();
        return true;
    }

    //写入文件
    bool writeFile(const std::string& fileName,const std::string& body)
    {
        //输出 二进制 文件截断，如果文件已存在，std::ios::trunc 会将其内容清空
        std::ofstream ofs(fileName,std::ios::out | std::ios::binary | std::ios::trunc);
        if(ofs.is_open() == false)
        {
            LOG_ERROR("打开{}文件失败",fileName); 
            return false;          
        }
        ofs.write(body.c_str(),body.size());
        if(ofs.good() == false)
        {
            LOG_ERROR("读取{}文件失败",fileName);
            ofs.close();
            return false;  
        }
        ofs.close();
        return true;
    }
}